package com.mengshu.mybatisplus.utils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.mengshu.mybatisplus.annotations.UniqueKey;
import com.mengshu.mybatisplus.basic.BasicMapper;
import com.mengshu.mybatisplus.basic.BasicPO;
import com.mengshu.mybatisplus.exceptions.UniqueKeyException;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 *     UniqueKey工具类
 * </p>
 *
 * @author liuning
 * @date 2:55 下午 2022/2/5
 */
@Slf4j
public class UniqueKeyUtils {

    /**
     * 判断唯一索引是否冲突
     *
     * @param t
     * @param mapper
     * @param <T>
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static <T extends BasicPO> void check(T t, BasicMapper<T> mapper) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        UniqueKey uniqueKey = t.getClass().getAnnotation(UniqueKey.class);
        // 类上有UniqueKey注解
        if (uniqueKey != null && uniqueKey.value().length > 0) {
            final LambdaQueryWrapper<T> query = new LambdaQueryWrapper<T>();
            final T search = (T) t.getClass().getDeclaredConstructor().newInstance();
            for (String fieldName : uniqueKey.value()) {

                query.eq(p -> FieldUtils.getFieldMethod(fieldName, p.getClass()), FieldUtils.getFieldValue(fieldName, t));
            }
            query.setEntity(search);

            checkBySaveOrUpdate(t, mapper, query, uniqueKey);
        }
        // 字段上有UniqueKey注解
        final List<Field> fields = new ArrayList<>();
        FieldUtils.getFields(t.getClass(), fields);
        for (Field field : fields) {
            uniqueKey = field.getAnnotation(UniqueKey.class);
            if (uniqueKey != null) {
                final LambdaQueryWrapper query = new LambdaQueryWrapper<T>()
                        .eq(p -> FieldUtils.getFieldMethod(field, p.getClass()), FieldUtils.getFieldValue(field, t));

                checkBySaveOrUpdate(t, mapper, query, uniqueKey);
            }
        }
    }

    /**
     * 判断是新增还是修改
     *
     * @param t
     * @param mapper
     * @param query
     * @param uniqueKey
     * @param <T>
     */
    public static  <T extends BasicPO> void checkBySaveOrUpdate(T t, BasicMapper<T> mapper, LambdaQueryWrapper<T> query, UniqueKey uniqueKey) {

        // 新增
        if (t.getId() == null) {
            if (mapper.selectOne(query) != null) {
                throw new UniqueKeyException(uniqueKey.message());
            }
        }

        // 修改
        else {
            final T target = mapper.selectOne(query);
            if (target != null && !Objects.equals(target.getId(), t.getId())) {
                throw new UniqueKeyException(uniqueKey.message());
            }
        }
    }
}
